<script setup lang="ts">
import {Feature, Map, View} from 'ol';
import TileLayer from 'ol/layer/Tile';
import {XYZ} from 'ol/source';
import '@/assets/styles/global.css'

import {defaults as Defaults, MousePosition, ScaleLine, ZoomSlider} from 'ol/control';
import {Location, MapLocation, Van, Avatar, Promotion} from '@element-plus/icons-vue'

import VectorLayer from "ol/layer/Vector";
import {Fill, Icon, Stroke, Style} from "ol/style";
import {ElButton, ElMessage, type FormInstance} from "element-plus";
import axios from "axios";
import {LineString, Point} from "ol/geom";
import VectorSource from "ol/source/Vector";
import {Select} from "ol/interaction";
import {never} from "ol/events/condition";
import CircleStyle from "ol/style/Circle";

var map = null;

// 当前鼠标所在经纬度
const currentPoint = ref()
// 是否可以进行坐标标点
const isBd = ref(false)
// 当前标点标记，0：普通标点， 1：起点， 2：终点
const result = ref(0)
// 中心点
const center = [106.332850, 29.616994];
// 地图的类型变量
const localTile = ref('roadmap')

// 地图类型接口
interface TileItem {
  name: string,
  id: string
}

// 地图类型列表
const tileList = ref<TileItem[]>([{
  name: '卫星图',
  id: 'satellite'
}, {
  name: '街道图',
  id: 'roadmap'
}])

// 在 script setup 中添加 天气信息
const weatherData = ref({province: '北京', temperature: '25°C', condition: '晴'});

// 途径点类型
interface DomainItem {
  key: number
  value: string
  lnglat: number[]
}

// 途径点列表
const dynamicValidateForm = reactive<{
  domains: DomainItem[]
}>({
  domains: []
})
// 绘制起点终点加载
const pointLoading = ref(false)
// 起点
const startPoint = ref({
  lnglat: [],
  address: '',
})
// 终点
const endPoint = ref({
  lnglat: [],
  address: '',
})

// 地图标准瓦片数据源
const baseSource = new XYZ({
  url: 'http://192.168.8.101/map/{z}/{x}/{y}.png',
})
// 标准瓦片图层
const baseLayer = new TileLayer({source: baseSource, visible: true})
// 卫星图层数据源
const sateliteSource = new XYZ({
  url: 'http://192.168.8.101/mix/satellite/{z}/{x}/{y}.png',
})
// 卫星图层
const sateliteLayer = new TileLayer({source: sateliteSource, visible: false})
// 卫星图道路图层数据源
const overlaySource = new XYZ({
  url: 'http://192.168.8.101/mix/overlay/{z}/{x}/{y}.png',
})
// 卫星图层道路图层
const overlayLayer = new TileLayer({source: overlaySource, visible: false})

// 创建一个矢量图层数据源，用于显示点标记。
let vectorSource = new VectorSource({
  features: []
});
// 矢量图层
let vectorLayer = new VectorLayer({
  source: vectorSource,
  style: new Style({
    image: new Icon({
      anchor: [0.5, 24], // 设置锚点，使得图标底部中心与点对齐
      anchorXUnits: 'fraction',
      anchorYUnits: 'pixels',
      src: '/bd.svg',
    }),
  }),
});
// 绘制起点矢量图层数据源
let dhStartSource = new VectorSource({
  features: []
});
// 绘制终点矢量图层
let dhStartVectorLayer = new VectorLayer({
  source: dhStartSource,
  style: new Style({
    image: new Icon({
      anchor: [0.5, 64], // 设置锚点，使得图标底部中心与点对齐
      anchorOrigin: 'top-right',
      anchorXUnits: 'fraction',
      anchorYUnits: 'pixels',
      offsetOrigin: 'top-right',
      offset: [0, -12],//偏移量设置
      scale: 0.5,  //图标缩放比例
      // opacity: 0.75,  //透明度
      src: '/start.svg',
    })
  }),
});
// 绘制终点矢量图层数据源
let dhEndSource = new VectorSource({
  features: []
});
// 绘制终点矢量图层
let dhEndVectorLayer = new VectorLayer({
  source: dhEndSource,
  style: new Style({
    image: new Icon({
      anchor: [0.5, 64], // 设置锚点，使得图标底部中心与点对齐
      anchorOrigin: 'top-right',
      anchorXUnits: 'fraction',
      anchorYUnits: 'pixels',
      offsetOrigin: 'top-right',
      offset: [0, -12],//偏移量设置
      scale: 0.5,  //图标缩放比例
      src: '/end.svg',
    })
  }),
});

// 地图路线矢量图层数据源
const lineSourceVector = new VectorSource();
// 地图路线矢量图层
const lineVectorLayer = new VectorLayer({
  source: lineSourceVector,
  style: function (feature) {
    var status = feature.get("status");
    var _color = "#8f8f8f";
    if (status === "拥堵") _color = "#e20000";
    else if (status === "缓行") _color = "#ff7324";
    else if (status === "畅通") _color = "#00b514";
    const coords = feature.getGeometry()!.getCoordinates();
    const styles = [
      new Style({
        stroke: new Stroke({
          color: _color,
          width: 8,
        }),
      })
    ];

    // 逐段添加箭头
    for (let i = 0; i < coords.length - 1; i += 20) {
      const start = coords[i];
      const end = coords[i + 1];
      const dx = end[0] - start[0];
      const dy = end[1] - start[1];
      const rotation = Math.atan2(-dy, dx); // 计算线段方向角度

      styles.push(
          new Style({
            geometry: new Point(end), // 箭头位于线段末端
            image: new Icon({
              src: '/arrow.svg', // 箭头图标路径
              anchor: [0.5, 0.5], // 调整图标锚点
              scale: 0.6,
              rotateWithView: true,
              rotation: rotation
            })
          })
      );
    }
    return styles;
  }
});
// 设置起点
const setStartPoint = async (coordate: number[]) => {
  dhStartSource.clear();
  //矢量元素
  var featureStart = new Feature({
    geometry: new Point(coordate),
    type: 'my-point',
    name: '起点',//自定义属性
  });
  // featureStart.setStyle(createFeatureStyle(featureStart, '起点'));
  dhStartSource.addFeature(featureStart);

  //起点
  //构造提交api起点坐标
  // start.value = GetCoordate(coordate);
  startPoint.value.langlat = coordate;
  const address = await reverseGeocode(coordate[1], coordate[0]);
  startPoint.value.address = address;
  // console.log("起点" + startPoint.value.address);
}
// 设置终点
const setEndPoint = async (coordate: number[]) => {
  //终点
  dhEndSource.clear();
  //矢量元素
  var featureEnd = new Feature({
    geometry: new Point(coordate),
    type: 'my-point',
    name: '终点',//自定义属性
  });
  // featureEnd.setStyle(createFeatureStyle(featureEnd, '终点'));
  dhEndSource.addFeature(featureEnd);
  const address = await reverseGeocode(coordate[1], coordate[0]);
  endPoint.value.langlat = coordate;
  endPoint.value.address = '';
  endPoint.value.address = address;
  // console.log("终点" + endPoint.value.address);
}

// 定义标点的点击事件
const popupPosition = ref({x: 0, y: 0})
const popupVisible = ref(false)
const popupPoint = ref<number[]>([])
// 关闭标点点击框
const closePopup = () => {
  popupVisible.value = false
}
// 初始化
const initMap = () => {
  map = new Map({
    // target: 'map', // 地图容器div的id
    target: 'map',
    layers: [baseLayer, sateliteLayer, overlayLayer, vectorLayer, lineVectorLayer, dhStartVectorLayer, dhEndVectorLayer, tempMarkerLayer],
    controls: Defaults({
      attribution: false,
      rotate: false,
      zoom: false,
    }).extend([
      new ScaleLine(), //比例尺控件
      new ZoomSlider(), //缩放滑块刻度控件
      new MousePosition({
        projection: '',
        coordinateFormat: function (coordinate) {
          currentPoint.value = coordinate;
          // return `东经${coordinate?.[0]} 北纬${coordinate?.[1]}`;
          return ''
        }
      }) //鼠标位置控件
    ]),
    view: new View({ // 地图视图
      center: center, // 地图中心点坐标
      // center: [86.139970, 36.328367],
      zoom: 10,
      // 限制地图缩放最大级别为18，最小级别为6
      minZoom: 5,
      maxZoom: 18,
      projection: "EPSG:4326", // 坐标系，有EPSG:4326和EPSG:3857
      constrainResolution: true,  // 设置缩放级别为整数
      smoothResolutionConstraint: false,  // 关闭无级缩放地图
    }),
  });

  map.on('pointermove', function (e) {
    const hit = map.forEachFeatureAtPixel(e.pixel, (feature) => {
      return feature.get('type') === 'my-point';
    });
    // 判断命中特定点要素时改变光标
    map.getTargetElement().style.cursor = hit ? 'pointer' : '';

    // 路线选择
    const pixel = map.getEventPixel(e.originalEvent);
    // 获取所有在该像素上的要素
    const features = map.getFeaturesAtPixel(pixel);
    // 过滤出路径线要素（LineString类型）
    const hitLineFeature = features?.find(
        (feature) => feature.getGeometry() instanceof LineString
    );
    if (hitLineFeature) {
      // 获取路径线几何对象
      const lineGeometry = hitLineFeature.getGeometry() as LineString;
      // 计算鼠标位置到路径线的最近点
      const closestPoint = lineGeometry.getClosestPoint(map.getCoordinateFromPixel(e.pixel));

      // 移除旧标记
      tempMarkerSource.clear();
      // 添加新标记到最近点
      const feature = new Feature(new Point(closestPoint));
      tempMarkerSource.addFeature(feature);
    } else {
      // 移除所有标记
      tempMarkerSource.clear();
    }
  });

// 添加鼠标事件
  map.on('click', async function (e) {
    const feature = map.forEachFeatureAtPixel(e.pixel, feature => feature)
    if (feature) {
      popupVisible.value = true
      // console.log('这是：', feature.get('description'))
      const coordinates = feature.getGeometry().getCoordinates()
      // popupContent.value = feature.get('name')

      const popupPixel = map.getPixelFromCoordinate(coordinates)
      popupPoint.value = coordinates
      popupPosition.value = {x: popupPixel[0]+10, y: popupPixel[1]}
    } else {
      if (popupVisible.value) {
        closePopup()
      } else {
        //获取坐标
        var coordate = e.coordinate;
        // 如果result为0，返回不做任何操作
        if (result.value == 0) {
          if (!isBd.value) {
            return;
          }
          let pointFeature = new Feature({
            geometry: new Point(e.coordinate),
            type: 'my-point',
          });
          vectorSource.addFeature(pointFeature)
          // return;
        } else {
          pointLoading.value = true;
          if (result.value == 1) {
            await setStartPoint(coordate);
          } else {
            await setEndPoint(coordate);
            ////请求数据
            if (startPoint.value.langlat.length == 0 || endPoint.value.langlat.length == 0) {
              ElMessage.error("请选择起点和终点");
              return;
            }
            getRouteResult(startPoint.value.langlat, endPoint.value.langlat);
          }
          pointLoading.value = false;
        }
        result.value = 0;
      }
    }
  });

}

// 新增：临时标记矢量源
const tempMarkerSource = new VectorSource();
// 新增：临时标记图层（需添加到地图）
const tempMarkerLayer = new VectorLayer({
  source: tempMarkerSource,
  style: new Style({
    image: new CircleStyle({
      radius: 4,
      fill: new Fill({color: 'rgb(255,255,255)'}),
      stroke: new Stroke({color: 'rgb(0,0,0)', width: 2})
    })
  })
});

// 经纬度转换成地址
const reverseGeocode = async (lat, lon) => {
  const url = `https://nominatim.openstreetmap.org/reverse?format=json&lat=${lat}&lon=${lon}&zoom=18&addressdetails=1`;
  var address = '';
  await fetch(url)
      .then(response => response.json())
      .then(data => {
        if (data && data.address) {
          address = data.display_name; // 或者使用data.address中的具体部分如data.address.city等
          console.log('Address:', address);
        } else {
          console.error('No address found');
        }
      })
      .catch(error => console.error('Error fetching geocode data:', error))

  return address;

}

// 导航方式
const activeName = ref('car')
//获取路径规划
const getRouteResult = (start, end) => {
  var data = {
    key: "c5cdf2ffefd81f23358df3005ad4b991",//申请的key值
    // key: '77652cd9a26359e9086df2e78d97571c',
    origin: start.join(","),//起点
    destination: end.join(","),//终点
    extensions: "all"
  };
  lineSourceVector.clear();
  axios.request({
    url: "https://restapi.amap.com/v3/direction/driving?origin=" + start.join(",") + "&destination=" + end.join(",") + "&extensions=all&output=json&key=c5cdf2ffefd81f23358df3005ad4b991",
    method: "get",
    // dataType: "jsonp",
    // data: data,
  }).then((result) => {
    // 从本地加载json数据
    // fetch('/route.json') // 直接访问public目录下的文件
    //     .then(response => response.json())
    //     .then(result => {
    var routes = result.data.route.paths[0];
    var steps = routes.steps;
    for (var i = 0; i < steps.length; i++) {
      var route = steps[i];
      var path = route.tmcs;
      for (var k = 0; k < path.length; k++) {
        var routePath = path[k];
        var distance = routePath.distance;
        var polyline = routePath.polyline.toString().split(";");
        var status = routePath.status;
        var polylineData = [];
        for (var j = 0; j < polyline.length; j++) {
          //将字符串拆成数组
          var realData = polyline[j].split(",");
          var coordinate = [realData[0], realData[1]];
          polylineData.push(coordinate);
        }
        var attribute = {
          distance: distance,
        };
        //线此处注意一定要是坐标数组
        var plygon = new LineString(polylineData);
        //线要素类
        var feature = new Feature({
          geometry: plygon,
          attr: attribute,
          status: status
        });
        lineSourceVector.addFeature(feature);
      }
    }
  })
}
// 设置地图图层,卫星图,街道图
const setTitleSource = (mid: string) => {
  if (mid === 'satellite') {
    baseLayer.setVisible(false)
    sateliteLayer.setVisible(true)
    overlayLayer.setVisible(true)
  } else {
    baseLayer.setVisible(true)
    sateliteLayer.setVisible(false)
    overlayLayer.setVisible(false)
  }
}


// 调用天气接口（示例）
const fetchWeather = async () => {
  const response = await fetch('https://restapi.amap.com/v3/weather/weatherInfo?city=110101&key=c5cdf2ffefd81f23358df3005ad4b991');
  response.json().then(data => {
    if (data.status === '1') {
      weatherData.value = {
        province: data.lives[0].province,
        temperature: data.lives[0].temperature + '°C',
        condition: data.lives[0].weather
      };
    }
  });
  // console.log(weatherData.value)
};

// 移除途径点
const removeDomain = (item: DomainItem) => {
  const index = dynamicValidateForm.domains.indexOf(item)
  if (index !== -1) {
    dynamicValidateForm.domains.splice(index, 1)
  }
}

// 添加途径点
const addDomain = () => {
  dynamicValidateForm.domains.push({
    key: Date.now(),
    value: '',
    lnglat: []
  })
}
// 清除标点和路径
const clearPoint = () => {
  vectorSource.clear()
  result.value = 0;
  startPoint.value = {
    langlat: [],
    address: undefined
  }
  endPoint.value = {
    langlat: [],
    address: undefined
  }
  // name = "";
  lineSourceVector.clear();
  dhStartSource.clear()
  dhEndSource.clear()
}
//定位到中心点
const toCenter = () => {
  map.getView().setCenter(center)
  map.getView().setZoom(6)
}

//保存小数点后六位
const GetCoordate = (coordate) => {
  var lng = coordate[0].toString();
  var lat = coordate[1].toString();
  var lngIndex = lng.indexOf(".") + 7;
  var latIndex = lat.indexOf(".") + 7;
  lng = lng.substring(0, lngIndex);
  lat = lat.substring(0, latIndex);
  var str = lng + "," + lat;
  console.log(str.toString());
  return str;
}
// 获取当前定位,计算到某个点的距离单位 km
const userLocation = ref(null)
const distance = ref(null)
const businessLocation = ref({latitude: 34.6522, longitude: 106.632850}) // 示例：某个点
// 当前定位
const getUserLocation = () => {
  if (navigator.geolocation) {
    navigator.geolocation.getCurrentPosition(position => {
      userLocation.value = {
        latitude: position.coords.latitude,
        longitude: position.coords.longitude
      };
      calculateDistance();
    }, error => {
      console.error("Error getting location:", error);
    });
  } else {
    console.error("Geolocation is not supported by this browser.");
  }
}
// 计算距离
const calculateDistance = () => {
  if (userLocation.value && businessLocation.value) {
    const R = 6371; // 地球半径，单位公里
    const dLat = degreesToRadians(businessLocation.value.latitude - userLocation.value.latitude);
    const dLon = degreesToRadians(businessLocation.value.longitude - userLocation.value.longitude);
    const a =
        Math.sin(dLat / 2) * Math.sin(dLat / 2) +
        Math.cos(degreesToRadians(userLocation.value.latitude)) * Math.cos(degreesToRadians(businessLocation.value.latitude)) *
        Math.sin(dLon / 2) * Math.sin(dLon / 2);
    const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    // 距离，单位公里
    distance.value = R * c; // 将结果存储在data中以便显示或进一步使用。
    console.log('距离', distance.value)
  } else {
    console.error("User location or business location is not set.");
  }
}
// 将角度转换为弧度
const degreesToRadians = (degrees: number) => {
  return degrees * (Math.PI / 180);
}
// 判断点是否相同
const getStatus = (a: number[], b: number[]) => {
  if (!a) {
    return true
  } else {
    // console.log("ab:",a, b)
    return b.length != 0 && a[0] != b[0] && a[1] != b[1]
  }
}

onMounted(() => {
  initMap();
  // fetchWeather()
});
</script>

<template>
  <div class="base-map">
    <div ref="mapContainer" id="map" style="width: 100%; height: 100%;"></div>
    <div v-if="popupVisible" :style="{ left: popupPosition.x + 'px', top: popupPosition.y + 'px' }"
         style="max-width: 480px;position: absolute;background-color: white;padding: 10px;">
      <el-button
          v-if="getStatus(startPoint.langlat,popupPoint)"
          type="primary"
          size="small"
          link
          @click="setStartPoint(popupPoint)">设为起点
      </el-button>
      <br>
      <el-button v-if="getStatus(endPoint.langlat,popupPoint)" type="primary"
                 link
                 size="small"
                 @click="setEndPoint(popupPoint)">设为终点
      </el-button>
    </div>
    <div class="overlay-switch">
      <el-tooltip content="回到中心点" placement="right" effect="light">
        <el-icon @click="toCenter" style="margin-bottom: 20px;">
          <Location></Location>
        </el-icon>
      </el-tooltip>

      <el-popover placement="top" :width="70" trigger="click">
        <template #reference>
          <el-icon>
            <MapLocation/>
          </el-icon>
        </template>
        <el-radio-group v-model="localTile" @change="setTitleSource">
          <div v-for="item in tileList">
            <el-radio :value="item.id">{{ item.name }}</el-radio>
          </div>
        </el-radio-group>
      </el-popover>


    </div>
    <div class="button-group">
      <el-button :type="isBd?'primary':'info'" @click="isBd=!isBd">标点</el-button>
      <el-button type="danger" @click="clearPoint">清除标点</el-button>
      <el-button type="info" @click="getUserLocation">获取当前位置</el-button>

    </div>
    <!--   导航 -->
    <div class="nav-group" v-loading="pointLoading">
      <el-form label-width="50px">
        <el-form-item label="起点"
                      prop="startPoint">
          <el-input readonly @click="result = 1" style="width: 150px;margin-right: 10px;"
                    :model-value="startPoint.address"
                    placeholder="点击再选择起点"></el-input>
        </el-form-item>
        <!--        <el-form-item style="display: flex;"-->
        <!--                      v-for="(domain, index) in dynamicValidateForm.domains"-->
        <!--                      :key="domain.key"-->
        <!--                      :label="'途径点' + (index+1)"-->
        <!--                      :prop="'domains.' + index + '.value'"-->
        <!--                      :rules="{-->
        <!--        required: true,-->
        <!--        message: '途径点不能为空',-->
        <!--        trigger: 'blur',-->
        <!--      }"-->
        <!--        >-->
        <!--          <el-input style="width: 150px;margin-right: 10px;" v-model="domain.value"/>-->
        <!--          <el-icon @click.prevent="removeDomain(domain)">-->
        <!--            <Remove/>-->
        <!--          </el-icon>-->
        <!--        </el-form-item>-->
        <el-form-item label="终点" style="display: flex;"
                      prop="endPoint">
          <el-input readonly @click="result=2" style="width: 150px;margin-right: 10px;"
                    :model-value="endPoint.address"
                    placeholder="点击再选择终点"></el-input>
          <!--          <el-icon @click.prevent="addDomain">-->
          <!--            <CirclePlus/>-->
          <!--          </el-icon>-->
        </el-form-item>
      </el-form>
      <div style="margin: 0 auto;width: 150px;">
        <el-tabs v-model="activeName">
          <el-tab-pane name="car">
            <template #label>
              <span class="custom-tabs-label">
                <el-icon><Van/></el-icon>
                <!--                <span>Route</span>-->
              </span>
            </template>
          </el-tab-pane>
          <el-tab-pane label="foot" name="second">
            <template #label>
              <span class="custom-tabs-label">
                <el-icon><Avatar/></el-icon>
                <!--                <span>Route</span>-->
              </span>
            </template>
          </el-tab-pane>
          <el-tab-pane label="gj" name="third">
            <template #label>
              <span class="custom-tabs-label">
                <el-icon><Promotion/></el-icon>
                <!--                <span>Route</span>-->
              </span>
            </template>
          </el-tab-pane>

        </el-tabs>
      </div>
    </div>
    <!-- 新增天气组件 -->
    <div class="weather-widget">
      <el-card class="weather-content" shadow="hover">
        <!--        <div >-->
        <!--          <el-icon>-->
        <!--            <Sunny/>-->
        <!--          </el-icon>-->
        <div>
          <p>{{ weatherData.province }}</p>
          <p>{{ weatherData.condition }}，{{ weatherData.temperature }}</p>
        </div>
        <!--        </div>-->
      </el-card>
    </div>
    <!--    <div id="menu_container" class="contextmenu">-->
    <!--      <ul>-->
    <!--        <li><a id="start" href="#" @click="setStart">设置起点</a></li>-->
    <!--        <li><a id="end" href="#" @click="setEnd">设置终点</a></li>-->
    <!--        <li><a id="clear" href="#" @click="clearPath">清除路径</a></li>-->
    <!--      </ul>-->
    <!--    </div>-->
  </div>
</template>

<style scoped lang="scss">
body {
  margin: 0;
  padding: 0;
}

.base-map {
  width: 100%;
  height: calc(100vh - 20px);
}

.overlay-switch {
  position: absolute;
  display: inline-block;
  height: auto;
  width: 20px;
  z-index: 900;
  //background-color: #fff;
  color: #333;
  text-align: center;
  left: 30px;
  bottom: 80px;
}

.button-group {
  position: absolute;
  display: inline-block;
  height: auto;
  //width: 60px;
  z-index: 900;
  //background-color: #fff;
  //color: #333;
  text-align: center;
  right: 30px;
  top: 30px;
}

.nav-group {
  position: absolute;
  display: inline-block;
  height: auto;
  //width: 20px;
  z-index: 900;
  background-color: #fff;
  //color: #333;
  text-align: center;
  left: 50px;
  top: 30px;
  padding: 8px;
}

.weather-widget {
  position: absolute;
  //height: 100px;
  z-index: 900;
  background-color: #fff;
  left: calc(60px + 300px); /* 与导航组件水平间隔 */
  top: 30px;
  padding: 8px;
}

.weather-content {
  height: 80px;
  display: flex;
  align-items: center;
  padding: 10px;
}

.contextmenu {
  position: absolute;
  top: 0;
  left: 0;
  width: 100px;
  //height: auto;
  z-index: 1000;
  background-color: #ffffff;
}

.contextmenu ul {
  width: 100%;
  padding: 6px 2px 0 2px;
  list-style: none;
}

.contextmenu > ul > li {
  width: 100%;
  text-align: center;
  padding: 5px 0;
}

.contextmenu > ul > li:hover {
  background-color: rgba(255, 0, 0, 0.5);
}

.tooltip {
  position: absolute;
  background: white;
  border: 1px solid #ccc;
  padding: 8px;
  pointer-events: none; /* 防止遮挡地图事件 */
  display: none; /* 默认隐藏 */
}

.clickable {
  cursor: pointer;
}
</style>